#include "Enesim.h"
#include "math.h"

/*
 * circle
 * compound
 * shape.background highlight.clip
 *                     highlight.shape
 *                     highlight.background
 */

typedef struct _Button01
{
	struct {
		Enesim_Renderer *background;
		Enesim_Renderer *compound;
		Enesim_Renderer *circle;
	} shape;
	struct {
		Enesim_Renderer *background;
		Enesim_Renderer *shape;
		Enesim_Renderer *clip;
	} highlight;
	Enesim_Color light;
	Enesim_Color dark;
	float radius;
	Enesim_Renderer_Sw_Fill fill;
} Button01;

static void _draw(Enesim_Renderer *r, int x, int y, unsigned int len, uint32_t *dst)
{
	Button01 *b;

	b = enesim_renderer_data_get(r);
	b->fill(b->shape.circle, x, y, len, dst);
}

static Eina_Bool _setup(Enesim_Renderer *r, Enesim_Renderer_Sw_Fill *fill)
{
	Button01 *b;
	Enesim_Matrix matrix;
	double ox, oy;

	b = enesim_renderer_data_get(r);
	/* the matrix */
	enesim_renderer_transformation_get(r, &matrix);
	enesim_renderer_transformation_set(b->shape.circle, &matrix);
	/* the origin */
	enesim_renderer_origin_get(r, &ox, &oy);
	enesim_renderer_origin_set(b->shape.circle, ox, oy);

	if (!enesim_renderer_sw_setup(b->shape.circle)) return EINA_FALSE;
	b->fill = enesim_renderer_sw_fill_get(b->shape.circle);
	if (!b->fill) return EINA_FALSE;

	*fill = _draw;

	return EINA_TRUE;
}

static void _cleanup(Enesim_Renderer *r)
{
	Button01 *b;

	b = enesim_renderer_data_get(r);
	enesim_renderer_sw_cleanup(b->shape.circle);
}

static void _free(Enesim_Renderer *r)
{
	Button01 *b;

	b = enesim_renderer_data_get(r);
	if (b->shape.background)
		enesim_renderer_unref(b->shape.background);
	if (b->shape.compound)
		enesim_renderer_unref(b->shape.compound);
	if (b->shape.circle)
		enesim_renderer_unref(b->shape.circle);
	if (b->highlight.background)
		enesim_renderer_unref(b->highlight.background);
	if (b->highlight.shape)
		enesim_renderer_unref(b->highlight.shape);
	if (b->highlight.clip)
		enesim_renderer_unref(b->highlight.clip);
}

static Enesim_Renderer_Descriptor _descriptor = {
	.sw_setup = _setup,
	.sw_cleanup = _cleanup,
	.free = _free,
};

void fancy_button01_light_color_set(Enesim_Renderer *r, Enesim_Color color)
{
	Enesim_Renderer *r1;
	Button01 *button;

	button = enesim_renderer_data_get(r);
	r1 = button->shape.background;
	enesim_renderer_stripes_even_color_set(r1, color);
}

void fancy_button01_dark_color_set(Enesim_Renderer *r, Enesim_Color color)
{
	Enesim_Renderer *r1;
	Button01 *button;

	button = enesim_renderer_data_get(r);
	r1 = button->shape.background;
	enesim_renderer_stripes_odd_color_set(r1, color);
}

void fancy_button01_radius_set(Enesim_Renderer *r, float radius)
{
	Enesim_Renderer *r1;
	Button01 *button;
	Enesim_Matrix t;
	float sa, ca;

	button = enesim_renderer_data_get(r);
	button->radius = radius;

	if (radius <= 4) return;

	r1 = button->shape.background;
	sa = sin(-30 * M_PI / 180.0);
	ca = cos(-30 * M_PI / 180.0);
	t.xx = ca;               t.xy = sa;               t.xz = 0;
	t.yx = -sa / (2 * button->radius);    t.yy = ca / (2 * button->radius);     t.yz = 0;
	t.zx = 0;                t.zy = 0;                t.zz = 1;
	enesim_renderer_transformation_set(r1, &t);

	r1 = button->highlight.background;
	sa = sin(120 * M_PI / 180.0);
	ca = cos(120 * M_PI / 180.0);
	t.xx = ca;                t.xy = sa;               t.xz = 0;
	t.yx = -sa / (1.2 * button->radius);   t.yy = ca / (1.2 * button->radius);   t.yz = 0;
	t.zx = 0;                 t.zy = 0;                t.zz = 1;
	enesim_renderer_transformation_set(r1, &t);

	r1 = button->highlight.shape;
	enesim_renderer_circle_radius_set(r1, 1.2 * button->radius);

	r1 = button->highlight.clip;
	enesim_renderer_circle_center_set(r1, button->radius, button->radius);
	enesim_renderer_circle_radius_set(r1, (0.925 * button->radius) - 2);

	r1 = button->shape.circle;
	enesim_renderer_circle_center_set(r1, button->radius, button->radius);
	enesim_renderer_circle_radius_set(r1, button->radius);
}

float fancy_button01_radius_get(Enesim_Renderer *r)
{
	Button01 *b;

	b = enesim_renderer_data_get(r);
	return b->radius;
}

Enesim_Renderer * fancy_button01_new(void)
{
	Enesim_Renderer *thiz, *r;
	Button01 *button;

	button = calloc(1, sizeof(Button01));
	if (!button) return NULL;

	/* a two-color stripe pattern */
	/* we'll use it as a simple gradient background via a transform */
	r = enesim_renderer_stripes_new();
	if (!r) goto shape_background_err;
	enesim_renderer_stripes_even_color_set(r, 0xff0077ff);
	enesim_renderer_stripes_odd_color_set(r, 0xff00ffff);
	enesim_renderer_stripes_even_thickness_set(r, 1);
	enesim_renderer_stripes_odd_thickness_set(r, 1);
	button->shape.background = r;

	/* another two-color stripe pattern */
	/* this will be our hilight gradient */
	r = enesim_renderer_stripes_new();
	if (!r) goto highlight_background_err;
	enesim_renderer_stripes_even_color_set(r, 0);
	enesim_renderer_stripes_odd_color_set(r, 0xffffffff);
	enesim_renderer_stripes_even_thickness_set(r, 1);
	enesim_renderer_stripes_odd_thickness_set(r, 1);
	button->highlight.background = r;

	/* a circle we'll fill with hf */
	r = enesim_renderer_circle_new();
	if (!r) goto highlight_shape_err;
	enesim_renderer_circle_center_set(r, 0, 0);
	enesim_renderer_shape_fill_renderer_set(r, button->highlight.background);
	enesim_renderer_shape_draw_mode_set(r, ENESIM_SHAPE_DRAW_MODE_FILL);
	button->highlight.shape = r;

	/* a circle we'll fill with hc */
	/* equivalent to clipping the above hc by it */
	/* this ic is what gives our hilight shape */
	r = enesim_renderer_circle_new();
	if (!r) goto highlight_clip_err;
	enesim_renderer_shape_fill_renderer_set(r, button->highlight.shape);
	enesim_renderer_shape_draw_mode_set(r, ENESIM_SHAPE_DRAW_MODE_FILL);
	button->highlight.clip = r;

	/* a composite paint consisting of two layers: */
	/* the base layer is the background gradient bf, */
	/* and on top of that is the hilight circle ic. */
	r = enesim_renderer_compound_new();
	if (!r) goto shape_compound_err;
	enesim_renderer_compound_layer_add(r, button->shape.background, ENESIM_FILL);
	enesim_renderer_compound_layer_add(r, button->highlight.clip, ENESIM_BLEND);
	button->shape.compound = r;

	/* a circle we'll fill with the composition above */
	/* this is the object we'll draw. */
	
	r = enesim_renderer_circle_new();
	if (!r) goto shape_circle_err;

	enesim_renderer_shape_outline_weight_set(r, 1);
	enesim_renderer_shape_outline_color_set(r, 0xff777777);
	enesim_renderer_shape_fill_renderer_set(r, button->shape.compound);
	enesim_renderer_shape_draw_mode_set(r, ENESIM_SHAPE_DRAW_MODE_STROKE_FILL);
	button->shape.circle = r;

	thiz = enesim_renderer_new(&_descriptor, button);
	if (!thiz) goto renderer_err;

	return thiz;

renderer_err:
	enesim_renderer_unref(button->shape.circle);
shape_circle_err:
	enesim_renderer_unref(button->shape.compound);
shape_compound_err:
	enesim_renderer_unref(button->highlight.clip);
highlight_clip_err:
	enesim_renderer_unref(button->highlight.shape);
highlight_shape_err:
	enesim_renderer_unref(button->highlight.background);
highlight_background_err:
	enesim_renderer_unref(button->shape.background);
shape_background_err:
	free(button);

	return NULL;
}


